package com.yunpuvip.sachet.rest.common.aop;


import cn.stylefeng.roses.core.reqres.response.ResponseData;
import com.yunpuvip.sachet.modular.core.ThreadContextValue;
import com.yunpuvip.sachet.modular.core.exception.RestException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * 拦截器：记录用户操作日志，检查用户是否登录……
 *
 * @author XuJijun
 * 来源:https://blog.csdn.net/clementad/article/details/52035199
 */
@Aspect
@Component
public class ControllerInterceptor {
    private static final Logger logger = LoggerFactory.getLogger(ControllerInterceptor.class);

    /**
     * 定义拦截规则：拦截com.xjj.web.controller包下面的所有类中，有@RequestMapping注解的方法。
     */
    @Pointcut("execution(* com.yunpuvip.sachet.rest.controller..*(..)) && (@annotation(org.springframework.web.bind.annotation.RequestMapping)" +
            "|| @annotation(org.springframework.web.bind.annotation.GetMapping)" +
            " || @annotation(org.springframework.web.bind.annotation.PostMapping )) ")
    public void controllerMethodPointcut() {
    }


    /**
     * 拦截器具体实现
     *
     * @param pjp
     * @return JsonResult（被拦截方法的执行结果，或需要登录的错误提示。）
     */
    @Around("controllerMethodPointcut()") //指定拦截器规则；也可以直接把“execution(* com.xjj.........)”写进这里
    public Object Interceptor(ProceedingJoinPoint pjp) throws Throwable {
        long beginTime = System.currentTimeMillis();
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        //获取被拦截的方法
        Method method = signature.getMethod();
        //获取被拦截的方法名
        String methodName = method.getName();

        //保存所有请求参数，用于输出到日志中
        Set<Object> allParams = new LinkedHashSet<>();
        String[] parameterNames = signature.getParameterNames();
        logger.info("请求参数：{}",parameterNames);
        logger.info("请求开始，方法：{}", methodName);


        Object result = null;
        // 一切正常的情况下，继续执行被拦截的方法

        try {
            result = pjp.proceed();
            ThreadContextValue.THREAD_UID.remove();
        } catch (Exception e) {
            ThreadContextValue.THREAD_UID.remove();
            // 如果不是 rest 异常 就抛出
            if (!(e instanceof RestException)) {
                throw e;
            }
            result = ResponseData.error(((RestException) e).getCode(), e.getMessage());
        }
        long costMs = System.currentTimeMillis() - beginTime;
        logger.info("{}请求结束，耗时：{}ms", methodName, costMs);
        return result;
    }


}
